home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Compendium Deluxe 2
/
LSD and 17bit Compendium Deluxe - Volume II.iso
/
a
/
prog
/
asmsrc
/
thesource-7.lha
/
Source
/
Misc.lha
/
misc
/
octree.c
< prev
Wrap
C/C++ Source or Header
|
1994-05-27
|
13KB
|
548 lines
Path: usenet.ee.pdx.edu!cs.uoregon.edu!sgiblab!swrinde!cs.utexas.edu!howland.reston.ans.net!xlink.net!newshost.uni-koblenz.de!usenet
From: lidl@informatik.uni-koblenz.de
Newsgroups: comp.graphics.algorithms
Subject: Re: Octree quantization method - how?
Date: 13 Apr 1994 08:25:56 GMT
Organization: University Koblenz / Germany
Lines: 535
Message-ID: <2ogaak$1ck@newshost.uni-koblenz.de>
Reply-To: lidl@infko.uni-koblenz.de
NNTP-Posting-Host: nepal.uni-koblenz.de
Hi,
i've implemented a version of the octree algorith, shown in the
Graphics Gems (the article isn't very correct, is it? :-))))
Well, let's start with the header:
/*----------------------------------------------------------*/
#define maxTreeDepth 7
#define maxDepthElems (maxTreeDepth+1)
#ifndef sqr
#define sqr(x) ((x)*(x))
#endif
typedef char *octreeLeaves[8];
typedef int colorSum[3];
typedef struct {
int colorCount,
children,
isLeaf;
colorSum RGB;
unsigned char midPoint[3],
colorIndex;
octreeLeaves nextBranch;
} octreeNode;
extern void initOctree(int,int);
extern void destroyNodes(octreeNode **);
extern void destroyOctree();
extern void newOctreeNode(octreeNode **);
extern void reduceTree();
extern void insertNewOctree(octreeNode **,unsigned char
*,unsigned
char *,int,int);
extern void generateEntry(octreeNode *);
extern int generatePalette(octreeNode *,unsigned char *);
extern unsigned char quant(octreeNode *,unsigned char *);
extern unsigned char *quantRgb(octreeNode *,unsigned char *);
extern int octreeBranch(unsigned char *,unsigned char *);
/*----------------------------------------------------------*/
Now, the main file:
/*----------------------------------------------------------*/
#import "octree.h"
#import <stdlib.h>
#import <ansi/math.h>
#import <objc/List.h>
int depthDist[maxDepthElems] = { 128,64,32,16,8,4,2,1 };
int representedNodes,
wantedColors,
reduceLevel,
paletteIndex,
reduceDir;
List *reducible[maxTreeDepth];
unsigned char *genPal,
*genPalBase;
octreeNode *lastLeaf;
void initOctree(int colorAnz,int reduceMode)
{
int initInd;
representedNodes = 0;
wantedColors = colorAnz;
reduceLevel = (maxTreeDepth-1);
reduceDir = reduceMode;
for ( initInd=0 ; initInd<maxTreeDepth ; initInd++ )
reducible[initInd] = [[List alloc] init];
}
void destroyNodes(octreeNode **root)
{
int delInd;
if (*root)
{
for ( delInd=0 ; delInd<8 ; delInd++ )
destroyNodes((octreeNode **)&((*root)->nextBranch[delInd]));
free(*root);
*root = NULL;
}
}
void destroyOctree()
{
int destroyInd;
for ( destroyInd=0 ; destroyInd<maxTreeDepth ; destroyInd++ )
{
[reducible[destroyInd] empty];
[reducible[destroyInd] free];
reducible[destroyInd] = NULL;
}
}
void newOctreeNode(octreeNode **newNode)
{
octreeNode *initNode;
int initInd;
initNode = (octreeNode *)malloc(sizeof(octreeNode));
for ( initInd=0 ; initInd<8 ; initInd++ )
initNode->nextBranch[initInd] = NULL;
initNode->colorCount = 0;
initNode->children = 0;
initNode->isLeaf = 0;
for ( initInd=0 ; initInd<3 ; initInd++ )
initNode->RGB[initInd] = 0;
initNode->midPoint[0] = 0;
initNode->midPoint[1] = 0;
initNode->midPoint[2] = 0;
*newNode = initNode;
}
void reduceTree()
{
int redCount,
redInd,
redPixels,
redMaxAdr,
redChild;
octreeNode *reduceTo,
*redTemp;
colorSum reduceSum;
while (!(redCount = [reducible[reduceLevel] count]))
reduceLevel--;
if (reduceDir) { redPixels = MAXINT; }
else { redPixels = 0; }
redMaxAdr = 0;
for ( redInd=0 ; redInd<redCount ; redInd++ )
{
reduceTo = (octreeNode *)[reducible[reduceLevel] objectAt:redInd];
if (reduceDir)
{
if (reduceTo->colorCount < redPixels)
{
redPixels = reduceTo->colorCount;
redMaxAdr = redInd;
}
}
else
{
if (reduceTo->colorCount > redPixels)
{
redPixels = reduceTo->colorCount;
redMaxAdr = redInd;
}
}
}
reduceTo = (octreeNode *)[reducible[reduceLevel]
removeObjectAt:redMaxAdr];
if (reduceTo)
{
for ( redInd=0 ; redInd<3 ; redInd++ )
reduceSum[redInd] = 0;
redChild = 0;
for ( redInd=0 ; redInd<8 ; redInd++ )
if (reduceTo->nextBranch[redInd])
{
redChild++;
redTemp = (octreeNode *)reduceTo->nextBranch[redInd];
reduceSum[0] += redTemp->RGB[0];
reduceSum[1] += redTemp->RGB[1];
reduceSum[2] += redTemp->RGB[2];
destroyNodes((octreeNode
**)&(reduceTo->nextBranch[redInd]));
reduceTo->nextBranch[redInd] = NULL;
}
reduceTo->isLeaf = 1;
reduceTo->RGB[0] = reduceSum[0];
reduceTo->RGB[1] = reduceSum[1];
reduceTo->RGB[2] = reduceSum[2];
representedNodes = (representedNodes - redChild + 1);
}
}
void insertNewOctree(octreeNode **actBranch,unsigned char *center,
unsigned char *insertRGB,int depth,int doReduce)
{
int newBranch,
distSub;
unsigned char newMid[3];
octreeNode *newNode;
if (!(*actBranch))
{
newOctreeNode(&newNode);
*actBranch = newNode;
if ((depth<maxTreeDepth) && (doReduce))
{
[reducible[depth] addObject:(id)newNode];
reduceLevel = depth;
}
memcpy(newNode->midPoint,center,3);
if (depth == maxTreeDepth)
{
representedNodes++;
newNode->isLeaf = 1;
lastLeaf = newNode;
}
}
else newNode = *actBranch;
newNode->colorCount++;
if ((*actBranch)->isLeaf)
{
newNode->isLeaf = 1;
newNode->children++;
newNode->RGB[0] += *(insertRGB);
newNode->RGB[1] += *(insertRGB+1);
newNode->RGB[2] += *(insertRGB+2);
while ((representedNodes>wantedColors) && (doReduce))
reduceTree();
}
else
{
newBranch = octreeBranch(newNode->midPoint,insertRGB);
memcpy(newMid,newNode->midPoint,3);
distSub = depthDist[depth];
if (newBranch & 0x0004) { newMid[0] += distSub; }
else { newMid[0] -= distSub; }
if (newBranch & 0x0002) { newMid[1] += distSub; }
else { newMid[1] -= distSub; }
if (newBranch & 0x0001) { newMid[2] += distSub; }
else { newMid[2] -= distSub; }
insertNewOctree((octreeNode **)&(newNode->nextBranch[newBranch]),
newMid,insertRGB,depth+1,doReduce);
}
}
void generateEntry(octreeNode *node)
{
int branchInd;
octreeNode *genTemp;
if (node->isLeaf)
{
node->colorIndex = paletteIndex++;
*genPal++ = (unsigned char)(node->RGB[0] / node->colorCount);
*genPal++ = (unsigned char)(node->RGB[1] / node->colorCount);
*genPal++ = (unsigned char)(node->RGB[2] / node->colorCount);
}
else
{
for ( branchInd=0 ; branchInd<8 ; branchInd++ )
{
genTemp = (octreeNode *)node->nextBranch[branchInd];
if (genTemp) generateEntry(genTemp);
}
}
}
int generatePalette(octreeNode *tree,unsigned char *palette)
{
paletteIndex = 0;
genPal = palette;
genPalBase = genPal;
generateEntry(tree);
return paletteIndex;
}
unsigned char quant(octreeNode *tree,unsigned char *color)
{
octreeNode *traverse,
*newNode;
int newDir,
actLevel,
minDist,
deltaR,
deltaG,
deltaB,
quantDelta,
findInd,
minPalEntry,
distSub;
unsigned char *actPalEntry,
newMid[3];
traverse = tree;
actLevel = 0;
while (!(traverse->isLeaf))
{
newDir = octreeBranch(traverse->midPoint,color);
newNode = (octreeNode *)traverse->nextBranch[newDir];
if (newNode)
{
traverse = newNode;
}
else
{
memcpy(newMid,traverse->midPoint,3);
distSub = depthDist[actLevel];
if (newDir & 0x0004) { newMid[0] += distSub; }
else { newMid[0] -= distSub; }
if (newDir & 0x0002) { newMid[1] += distSub; }
else { newMid[1] -= distSub; }
if (newDir & 0x0001) { newMid[2] += distSub; }
else { newMid[2] -= distSub; }
insertNewOctree((octreeNode
**)&(traverse->nextBranch[newDir]),
newMid,
color,
actLevel+1,
0);
traverse = lastLeaf;
traverse->isLeaf = 1;
minPalEntry = 0;
actPalEntry = genPalBase;
minDist = MAXINT;
for ( findInd=0 ; findInd<paletteIndex ; findInd++ )
{
deltaR = *(color);
deltaR -= *actPalEntry++;
deltaG = *(color+1);
deltaG -= *actPalEntry++;
deltaB = *(color+2);
deltaB -= *actPalEntry++;
quantDelta = (sqr(deltaR) + sqr(deltaG) +
sqr(deltaB));
if (quantDelta<minDist)
{
minDist = quantDelta;
minPalEntry = findInd;
}
}
traverse->colorIndex = minPalEntry;
}
actLevel++;
}
return traverse->colorIndex;
}
unsigned char *quantRgb(octreeNode *tree,unsigned char *color)
{
octreeNode *traverse,
*newNode;
int newDir,
actLevel,
minDist,
deltaR,
deltaG,
deltaB,
quantDelta,
findInd,
minPalEntry,
distSub;
unsigned char *actPalEntry,
newMid[3];
traverse = tree;
actLevel = 0;
while (!(traverse->isLeaf))
{
newDir = octreeBranch(traverse->midPoint,color);
newNode = (octreeNode *)traverse->nextBranch[newDir];
if (newNode)
{
traverse = newNode;
}
else
{
memcpy(newMid,traverse->midPoint,3);
distSub = depthDist[actLevel];
if (newDir & 0x0004) { newMid[0] += distSub; }
else { newMid[0] -= distSub; }
if (newDir & 0x0002) { newMid[1] += distSub; }
else { newMid[1] -= distSub; }
if (newDir & 0x0001) { newMid[2] += distSub; }
else { newMid[2] -= distSub; }
insertNewOctree((octreeNode
**)&(traverse->nextBranch[newDir]),
newMid,
color,
actLevel+1,
0);
traverse = lastLeaf;
traverse->isLeaf = 1;
minPalEntry = 0;
actPalEntry = genPalBase;
minDist = MAXINT;
for ( findInd=0 ; findInd<paletteIndex ; findInd++ )
{
deltaR = *(color);
deltaR -= *actPalEntry++;
deltaG = *(color+1);
deltaG -= *actPalEntry++;
deltaB = *(color+2);
deltaB -= *actPalEntry++;
quantDelta = (sqr(deltaR) + sqr(deltaG) +
sqr(deltaB));
if (quantDelta<minDist)
{
minDist = quantDelta;
minPalEntry = findInd;
}
}
traverse->colorIndex = minPalEntry;
}
actLevel++;
}
return traverse->midPoint;
}
int octreeBranch(unsigned char *mid,unsigned char *direction)
{
int actBranch;
actBranch = 0;
if (*(mid) <= *(direction) ) actBranch |= 0x0004;
if (*(mid+1) <= *(direction+1)) actBranch |= 0x0002;
if (*(mid+2) <= *(direction+2)) actBranch |= 0x0001;
return actBranch;
}
/*----------------------------------------------------------*/
Ok, let's look a litle bit closer into the code. There's only one
Next-dependent part in the code: #import "List.h". But the name
corresponds to the meaning I think. There are seven functions for
using the List ("methods" in Objective-C):
alloc = allocate a new List object
init = initialize it
empty = empty the list without freeing the elements
free = discard the list
addObject= append a new element to the list (always at the
end of the list; always of the ID, a special kind
of a pointer)
removeObjectAt= remove the element at position i
objectAt = get the i-th element of the list
Using the code is fairly simple:
unsigned char centerPoint[3];
unsigned char *source,
*pixel,
colorIndex,
*palette;
octreeNode *tree;
int quantWidth,
quantHeight,
xLoop,
yLoop,
initOctree(colorCount,reduceMode);
/* colorCount = maximal number of colors in the */
/* resulting image */
/* reduceMode = algorithm, used when reducing */
/* the tree: 0 = reduce nodes with */
/* the highest color */
/* count */
/* 1 = reduce nodes with */
/* the lowest color */
/* count */
tree = NULL;
centerPoint[0] = 0;
centerPoint[1] = 0;
centerPoint[2] = 0;
/* Coordinates of the octree-root */
pixel = source;
for ( yLoop=0 ; yLoop<quantHeight ; yLoop++ )
for ( xLoop=0 ; xLoop<quantWidth ; xLoop++ )
{
insertNewOctree(&tree,centerPoint,pixel,0,1);
pixel += 3;
}
palette = (byte *)malloc(3*colorAnz);
memset(palette,0,3*colorAnz);
*entrysUsed = (generatePalette(tree,palette)+1);
pixel = target;
for ( yLoop=0 ; yLoop<quantHeight ; yLoop++ )
{
for ( xLoop=0 ; xLoop<quantWidth ; xLoop++ )
{
colorIndex = quant(tree,source);
*pixel++ = colorIndex;
source += 3;
}
}
destroyNodes(&tree);
destroyOctree();
Pffffffft, that's all. Any question? No? Ok.
Hope, it helps.
Bye
LIDL